﻿#region license
// KenEgozi.com - my blog engine
// This project is licensed under the MIT License
//
//Copyright (c) 2007, Ken Egozi
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
#endregion

using System;
using System.Collections.Generic;
using System.Security;
using System.Text;
using System.Web;
using CookComputing.XmlRpc;
using KenEgozi.Com.Domain.Aggregates.Post;
using KenEgozi.Com.Domain.Aggregates.Tag;
using KenEgozi.Com.Domain.Interfaces.Factories;
using KenEgozi.Com.Domain.Repositories;
using KenEgozi.Com.Weblog.Services;
using NHibernate.Expression;
using System.IO;

using KenEgozi.Com.Weblog.Application.API.Blogger;
using KenEgozi.Com.Weblog.Application.API.MetaWeblog;
using Rhino.Commons;

namespace KenEgozi.Com.Weblog.Application.API
{
	public class EditService : XmlRpcService, IMetaWeblog, IBlogger
	{
		readonly IPostFactory postFactory;
		readonly ITagFactory tagFactory;
		readonly ICachedItemsService cachedItemsService;
		readonly ISecurityService securityService;

		public EditService()
		{
			postFactory = IoC.Resolve<IPostFactory>();
			cachedItemsService = IoC.Resolve<ICachedItemsService>();
			tagFactory = IoC.Resolve<ITagFactory>();
			securityService = IoC.Resolve<ISecurityService>();
		}

		#region IMetaWeblog Members

		object IMetaWeblog.editPost(string postid, string username, string password, PostInfo postInfo, bool publish)
		{
			AssertCredentials(username, password);
			int postId = int.Parse(postid);
			Post post = Repository.Posts.Get(postId);
			if (post == null)
				throw new ApplicationException("Post not found");

			post.Title = postInfo.title;
			post.Content = postInfo.description;
			post.Tags.Clear();

			List<Tag> tags = Repository.Tags.FindAll() as List<Tag>;
			With.Transaction(delegate
         	{
         		if (postInfo.categories != null && tags != null)
         			foreach (string tagName in postInfo.categories)
         			{
         				Tag tag = tags.Find(delegate(Tag t) { return t.Name == tagName; });
         				if (tag == null)
         				{
         					tag = tagFactory.Create(tagName);
         					Repository.Tags.Save(tag);
         				}

         				post.Tags.Add(tag);
         			}
         		Repository.Posts.Save(post);
         	});
			return true;
		}

		CategoryInfo[] IMetaWeblog.getCategories(string blogid, string username, string password)
		{
			AssertCredentials(username, password);
			ICollection<Tag> tags = Repository<Tag>.FindAll(Order.Asc("Name"));
			List<CategoryInfo> categories = new List<CategoryInfo>();
			foreach (Tag tag in tags)
			{
				CategoryInfo category = new CategoryInfo();
				category.categoryid = tag.UrlFriendlyName;
				category.description = tag.Name;
				category.title = tag.Name;
				category.htmlUrl = GetBlogUrl() + "/Tag/" + tag.UrlFriendlyName + ".aspx";
				category.rssUrl = GetBlogUrl() + "/Tag/" + tag.UrlFriendlyName + ".aspx?SyndicationType=Atom";
				categories.Add(category);
			}
			return categories.ToArray();
		}

		PostInfo IMetaWeblog.getPost(string postid, string username, string password)
		{
			AssertCredentials(username, password);
			int postId = int.Parse(postid);
			Post post = Repository.Posts.Get(postId);
			if (post == null)
				return new PostInfo();
			PostInfo postInfo = PostToPostInfo(post);
			return postInfo;
		}

		PostInfo[] IMetaWeblog.getRecentPosts(string blogid, string username, string password, int numberOfPosts)
		{
			AssertCredentials(username, password);

			ICollection<Post> posts = Repository.Posts.FindRecent(numberOfPosts);

			List<PostInfo> postInfos = new List<PostInfo>(posts.Count);
			foreach (Post post in posts)
				postInfos.Add(PostToPostInfo(post));
			return postInfos.ToArray();
		}

		string IMetaWeblog.newPost(string blogid, string username, string password, PostInfo postInfo, bool publish)
		{
			AssertCredentials(username, password);

			Post post = postFactory.Create(postInfo.title, postInfo.description);
			List<Tag> tags = Repository<Tag>.FindAll() as List<Tag>;
			With.Transaction(delegate
			{
				if (postInfo.categories != null && tags != null)
					foreach (string tagName in postInfo.categories)
					{
						Tag tag = tags.Find(delegate(Tag t) { return t.Name == tagName; });
						if (tag == null)
						{
							tag = tagFactory.Create(tagName);
							Repository.Tags.Save(tag);
						}

						post.Tags.Add(tag);
					}
				Repository.Posts.Save(post);
			});
			cachedItemsService.Invalidate(Keys.Cache.TagCloud);
			cachedItemsService.Invalidate(Keys.Cache.Archive);
			cachedItemsService.Invalidate(Keys.Cache.Stats);
			return post.Id.ToString();
		}

		UrlData IMetaWeblog.newMediaObject(string blogid, string username, string password, FileData file)
		{
			AssertCredentials(username, password);

			string extension = Path.GetExtension(file.name);

			string[] fileNameParts = file.name.Split('/');

//			string originalFileName = Path.GetFileNameWithoutExtension(fileNameParts[fileNameParts.Length - 1]);
//			string fileName = HttpUtility.UrlEncode(originalFileName);

			StringBuilder url = new StringBuilder();
			for (int i = 0; i < fileNameParts.Length - 1; ++i)
				url.Append(fileNameParts[i]).Append("/");
			url.Append(Guid.NewGuid().ToString()).Append(extension);

			string path = "/Content/Binary/" + url;

			string serverPath = Context.Server.MapPath("~" + path);

			string directory = Path.GetDirectoryName(serverPath);
			if (!Directory.Exists(directory))
				Directory.CreateDirectory(directory);

			File.WriteAllBytes(serverPath, file.bits);

			UrlData urlData = new UrlData();
			urlData.url = GetBlogUrl() + path;
			return urlData;
		}

		bool IBlogger.blogger_deletePost(string appKey, string postid, string username, string password, bool publish)
		{
			AssertCredentials(username, password);
			int postId = int.Parse(postid);
			Post post = Repository.Posts.Get(postId);
			With.Transaction(delegate
			{
				Repository.Posts.Delete(post);
			});
			return true;
		}

		BlogInfo[] IBlogger.blogger_getUsersBlogs(string appKey, string username, string password)
		{
			AssertCredentials(username, password);
			BlogInfo b = new BlogInfo();
			b.blogid = "1";
			b.blogName = "Ken Egozi";
			b.url = GetBlogUrl();
			return new BlogInfo[] { b };
		}
		/*
		string getTemplate(string appKey, string blogid, string username, string password, string templateType)
		{
			return "";
		}
		 * */
		#endregion

		private static PostInfo PostToPostInfo(Post post)
		{
			PostInfo postInfo = new PostInfo();
			List<string> categories = new List<string>(post.Tags.Count);
			foreach (Tag tag in post.Tags)
				categories.Add(tag.Name);
			postInfo.categories = categories.ToArray();
			postInfo.dateCreated = post.Lifecycle.CreationDate;
			postInfo.description = post.Content;
			postInfo.title = post.Title;
			postInfo.permalink = GetBlogUrl() + "/" + post.Permalink;
			postInfo.postid = post.Id.ToString();
			return postInfo;
		}

		private void AssertCredentials(string username, string password)
		{
			if (securityService.IsAuthenticated(username, password) == false)
				throw new SecurityException("Invalid credentials");
		}

		private static string GetBlogUrl()
		{
			HttpRequest request = HttpContext.Current.Request;
			return
				request.Url.Scheme + "://" +
				request.Url.Authority +
				request.ApplicationPath;
		}
		#region IBlogger Members


		string IBlogger.blogger_getTemplate(string appKey, string blogid, string username, string password, string templateType)
		{
			throw new NotImplementedException("IBlogger.blogger_getTemplate");
		}


		bool IBlogger.blogger_setTemplate(string appKey, string blogid, string username, string password, string template, string templateType)
		{
			return true;
		}

		#endregion

	}
}
